package com.online.taxi.order.implementation.redis;

import com.online.taxi.order.implementation.LockKey;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

/**
 * @Author:jiangqikun
 * @Date:2022/8/21 14:38
 **/
@Service
@Data
public class RedisLock {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    private LockKey lockKey;

    public void lock() {
        // 1、尝试加锁
        if(tryLock()) {
            return;
        }
        // 2.休眠
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 3.递归再次调用
        lock();
    }

    /**
     * 	非阻塞式加锁，成功，就成功，失败就失败。直接返回
     */
    public boolean tryLock() {
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey.getOrderId().intern(), lockKey.getDriverId(), 50, TimeUnit.SECONDS);
        if(Boolean.FALSE.equals(result)) {
            return Boolean.FALSE;
        }
        // 开个子线程，原来时间N，每个n/3，去续上n
        renewLock(lockKey.getOrderId().intern(), lockKey.getDriverId(), 10);
        return Boolean.TRUE;
    }

    public void unlock() {
        //这种释放锁有，可能释放了别人的锁。
        // stringRedisTemplate.deletelockKey.getDriverId().intern());
        if((lockKey.getOrderId()).equals(stringRedisTemplate.opsForValue().get(lockKey.getDriverId().intern()))) {
            stringRedisTemplate.delete(lockKey.getDriverId().intern());
        }
    }

    /**
     * 续租
     */
    @Async   // 这个注解表示另外启动一个线程
    public void renewLock(String key, String value, int time) {
        String v = stringRedisTemplate.opsForValue().get(key);
        if (v.equals(value)){
            int sleepTime = time / 3;
            try {
                Thread.sleep(sleepTime * 1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stringRedisTemplate.expire(key,time,TimeUnit.SECONDS);
            renewLock(key,value,time);
        }
    }

}
